# -*- coding: utf-8 -*-
import requests
import random
import json
import coordTransform as coord
import wx
import time,datetime, sys
from requests_futures.sessions import FuturesSession
from concurrent.futures import ThreadPoolExecutor
import xingzhengqu

def make_onerequests(url):
	while 1:
		try:
			data = requests.get(url, timeout=1)
			return data.text
		except:
			#print('error xingzhengqu')
			pass

def getadcode(adcode_sheng, x, gaodekey):
	#输入省的adcode，返回市列表
	url = 'https://restapi.amap.com/v3/config/district?key=%s&keywords=%s' % (gaodekey, adcode_sheng)
	data = make_onerequests(url)
	l = json.loads(data)['districts'][0]['districts']
	lshi = [x['name'] for x in l]
	lshicode = [x['adcode'] for x in l]
	return lshicode

def gettime():
	return time.strftime("%H:%M:%S", time.localtime())

def burnloc(lng1, lat1, lng2, lat2):
	#输入左上和右下角经纬度点对，返回矩形点集
	lng1, lat1, lng2, lat2 = [int(x * 100) for x in [lng1, lat1, lng2, lat2]]
	lout = []
	llng = list(range(lng1, (lng2 + 1), 1))
	llat = list(range(lat2, (lat1 + 1), 1))
	for i in range(len(llng) - 1):
		lngone1 = llng[i]
		lngone2 = lngone1 + 1
		for j in range(len(llat) - 1):
			latone1 = llat[j]
			latone2 = latone1 + 1
			p1 = (round((lngone1 / 100), 2), round((latone1 / 100), 2))
			p2 = (round((lngone2 / 100), 2), round((latone2 / 100), 2))
			lout.append((p1, p2))
	return lout
	
def output(outputtext, s):
	outputtext.AppendText(s)

def requestone(url, outputtext):
	#进行一次访问
	while 1:
		try:
			data = requests.get(url, timeout=1)
			data = data.text
			data = json.loads(data)
			if data['info'] == 'OK':
				break
			if data['info'] == 'DAILY_QUERY_OVER_LIMIT':
				wx.CallAfter(outputtext.printmsg, '今日访问次数超过当天限制\n')
				return 'OVER_LIMIT'
			else:
				print(data['info'])
		except:
			#s = '%s 网络不稳定\n' % gettime()
			#wx.CallAfter(outputtext.printmsg, s)
			print(23)
			pass
	return data
	
def jiexiloc(s):
	#转坐标系
	lng, lat = s.split(',')
	lng, lat = coord.gcj02_to_wgs84(float(lng), float(lat))
	lng = round(lng, 10)
	lat = round(lat, 10)
	return (str(lng), str(lat))
	
def check_in_out(data, citycode, adcode):
	if adcode != 'all':
		if int(adcode) == int(data['pois'][0]['adcode']):
			return True
	else:
		if str(citycode)[:4] == str(data['pois'][0]['adcode'])[:4]:
			return True
	return False
	
def jiexidata(data, sep, lname):
	#解析json数据
	lout = ''
	l = []
	for poi in data['pois']:
		loc = jiexiloc(poi['location'])
		poi['lng'] = loc[0]
		poi['lat'] = loc[1]
		poi['rating'] = poi['biz_ext']['rating']
		poi['cost'] = poi['biz_ext']['cost']
		if 'deep_info' in poi:
			poi['taste_rating'] = poi['deep_info']['taste_rating']
			poi['environment_rating'] = poi['deep_info']['environment_rating']
			poi['service_rating'] = poi['deep_info']['service_rating']
		else:
			poi['taste_rating'] = 'null'
			poi['environment_rating'] = 'null'
			poi['service_rating'] = 'null'
		l.append(poi)
		
		
	for poi in l:
		ltext = [poi[x] for x in lname]
		ltext2 = []
		for text in ltext:
			if text == [ ]:
				text = 'null'
			elif isinstance(text, list):
				text = '|'.join(text)
			else:
				pass
			ltext2.append(text)
		ltext2 = [x.replace(',',';') for x in ltext2]
		lout = lout + sep.join(ltext2) + '\n'
	return lout
	
class Xingzhengqu(object):
	#如果用户输入了行政区则获取行政区边界, 得到经纬度列表
	def __init__(self, adcode, lloc, outputtext, key):
		self.adcode = adcode
		self.lloc = lloc #矩形点集
		self.outputtext = outputtext
		self.key = key
		self.cal()

	def cal(self):
		#返回矩形点集
		if self.adcode == 'null':
			#用户没有输入行政区
			self.lloc_choice = self.lloc
			self.polygon = 'null'
		else:
			#用户输入了行政区
			self.getpolygon()
			self.getlocout()
		
	def getpolygon(self):
		#高德请求获取行政区polygon
		lout = []
		url = 'http://restapi.amap.com/v3/config/district?key=%s&keywords=%s&subdistrict=0&extensions=all' % (self.key, self.adcode)
		print(gettime())
		data = requestone(url, self.outputtext)
		if data == 'OVER_LIMIT':
			wx.CallAfter(self.outputtext.printmsg, '今日访问次数超过当天限制\n')
			exit()
		data = data['districts'][0]['polyline']
		lline = data.split('|')
		self.llng, self.llat = [], []
		num = 0
		for line in lline:
			num += 1
			lloc = line.split(';')
			lone = [(x.split(',')[0],x.split(',')[1]) for x in lloc]
			loneutm = []
			for one in lone:
				lnggcj, latgcj = float(one[0]), float(one[1])
				lngwgs, latwgs = coord.gcj02_to_wgs84(lnggcj, latgcj)
				self.llng.append(lngwgs)
				self.llat.append(latwgs)
		
	def getlocout(self):
		#获取最终输出的矩形列表
		self.lloc_choice = []
		if self.lloc == 'null':
			#用户没有输入经纬度，只根据行政区生成矩形点集
			lngmax = max(self.llng)
			lngmin = min(self.llng)
			latmax = max(self.llat)
			latmin = min(self.llat)
			lngmin, latmax, lngmax, latmin = [round(x, 2) for x in [lngmin, latmax, lngmax, latmin]]
			self.lloc = burnloc(lngmin, latmax, lngmax, latmin)
			

class Gaode(object):
	def __init__(self, dic, outputtext):
		self.dic = dic
		self.outputtext = outputtext
		self.poinum = 0
		self.getpara()
		self.buildkey()
		self.buildadcode()
		self.buildlloc()
		self.buildcate()
		self.buildcateout()
		self.writecolumns()
		self.cal()
		
	def buildkey(self):
		#如果用户输入了key，用用户自己的key，否则用默认的key
		self.lkey = self.dic['gaodekey']
		
		
	def getkey(self):
		#随机返回一个key
		return random.sample(self.lkey,1)[0]
		
	def buildadcode(self):
		#返回最小级别的code
		if self.dic['xian'] == 'all':
			self.adcode = self.dic['shi']
		else:
			self.adcode = self.dic['xian']
		
	def getpara(self):
		#获取用户输入的参数
		self.keywords = self.dic['keywords']
		self.lloc = self.dic['lloc']
		self.pathout = self.dic['path']
		self.type = self.dic['type']
				
	def buildlloc(self):
		#如果用户输入了经纬度，生成经纬度点对集合
		if self.lloc != 'null':
			self.lloc = [round(float(x), 2) for x in self.lloc]
			lng1, lat1, lng2, lat2 = self.lloc
			self.lloc_out = burnloc(lng1, lat1, lng2, lat2)
		else:
			self.lloc_out = 'null'
			
	def buildcateout(self):
		#构建输出的列名
		dic = {
			'唯一ID':'id',
			'POI名称':'name',
			'POI类型':'type',
			'POI类型编号':'typecode',
			'行业类型':'biz_type',
			'地址':'address',
			'经度':'lng',
			'纬度':'lat',
			'POI所在省份名称':'pname',
			'POI所在城市名称':'cityname',
			'区域编码':'adname',
			'商家电话':'tel',
			'店铺评分':'rating',
			'人均消费':'cost',
			'口味评分':'taste_rating',
			'环境评分':'environment_rating',
			'服务评分':'service_rating',
		}
		self.cateout = [dic[x] for x in self.dic['cateout']]
		
			
	def buildxingzhengqu(self):
		#如果用户输入了行政区，没有输入经纬度，根据行政区生成矩形点集
		#如果用户输入了行政区，也输入了经纬度
		Xzq = Xingzhengqu(self.adcode, self.lloc_out, self.outputtext, self.lkey[0])
		self.lloc = Xzq.lloc
	
	def buildurlbase(self):
		#选择调用的高德url
		self.urlbase = 'http://restapi.amap.com/v3/place/polygon'

			
	def buildcate(self):
		#生成用户选择的类别，5个类别为一组
		lcate = self.dic['cate']
		self.lcate, lone = [], []
		for i in lcate:
			lone.append(i)
			if len(lone) == 5:
				s = '|'.join(lone)
				self.lcate.append(s)
				lone = []
		if len(lone) != 0:
			s = '|'.join(lone)
			self.lcate.append(s)
			
	def writecolumns(self):
		#写标题
		if self.type == 'csv':
			self.sep = ','
		elif self.type == 'txt':
			self.sep = '\t'
		self.pathout.replace(':\\',':\\\\')
		self.pathout.replace('\\\\','\\')
		print(self.pathout)
		#lname = ['id', 'name', 'type','typecode','biz_type','location','lng','lat', 'tel','pname','cityname','adname','importance', 'shopid', 'shopinfo', 'poiweight']
		with open(self.pathout, 'w') as o:
			s = self.sep.join(self.dic['cateout']) + '\n'
			o.write(s)
	
	def getpageall2(self, url):
		#输入一个url,返回加上页数的所有url
		#print(url)
		print(gettime())
		data = requestone(url, self.outputtext)
		
		if data == 'OVER_LIMIT':
			exit()
		count = int(data['count'])
		if count != 0:
			#先把第一页的内容输出到csv
			s = jiexidata(data, self.sep, self.cateout)
			
			with open(self.pathout, 'a') as o:
				o.write(s)
			pageall = int(count / 20)
			if count % 20 != 0:
				pageall += 1
			if pageall != 1:
				#如果有第二页，返回从第二页以后的url
				lpage = range(2, (pageall + 1))
				url = url.replace('&page=1','')
				lurl = [url + '&key={}'.format(self.getkey())]
				lurl = [url + '&page={}'.format(x) for x in lpage]
				return lurl
				
			else:
				return []
		else:
			return []
	
	def getpageall(self, url):
		#输入一个url,返回加上页数的所有url
		#print(url)
		print(gettime())
		data = requestone(url, self.outputtext)
		
		if data == 'OVER_LIMIT':
			exit()
		count = int(data['count'])
		if count != 0:
			if check_in_out(data,self.dic['shi'], self.dic['xian']):
				#先把第一页的内容输出到csv
				s = jiexidata(data, self.sep, self.cateout)
				with open(self.pathout, 'a') as o:
					o.write(s)
				pageall = int(count / 20)
				if count % 20 != 0:
					pageall += 1
				if pageall != 1:
					#如果有第二页，返回从第二页以后的url
					lpage = range(2, (pageall + 1))
					url = url.replace('&page=1','')
					lurl = [url + '&key={}'.format(self.getkey())]
					lurl = [url + '&page={}'.format(x) for x in lpage]
					return lurl
				else:
					return []
			else:
				return []
		else:
			return []
			
	def requestmany(self, lurl):
		#发送并发请求，并写入数据
		print(gettime())
		out = ''
		session = FuturesSession(executor=ThreadPoolExecutor(max_workers=len(lurl)))
		while 1:
			try:
				lresponse = [session.get(x, timeout=1) for x in lurl]
				lresponse = [x.result() for x in lresponse]
				lstatus_code = [x.status_code for x in lresponse]
				break
			except:
				pass
				#print(222)
		
		#print(lstatus_code)
		ldata = [x.content for x in lresponse]
		for i in range(len(lurl)):
			url = lurl[i]
			status_code = lstatus_code[i]
			data = ldata[i]
			data = self.checkdata(data, status_code, url)
			datapoi = jiexidata(data, self.sep, self.cateout)
			out = out + datapoi
		with open(self.pathout, 'a') as o:
			o.write(out.replace('\u2641',''))
		
			
	def checkdata(self, data, status_code, url):
		#检查返回的数据是否为None，状态码，info
		if status_code != 200:
			data = requestone(url, self.outputtext)
		else:
			data = json.loads(str(data, encoding = "utf-8") )
			if data['info'] == 'DAILY_QUERY_OVER_LIMIT':
				wx.CallAfter(self.outputtext.printmsg, '今日访问次数超过当天限制\n')
				exit()
			if data['info'] != 'OK':
				data = requestone(url, self.outputtext)
		return data
	
	def cal(self):
		self.buildurlbase()
		s = '%s 开始搜索\n' % gettime()
		wx.CallAfter(self.outputtext.printmsg, s)
		if self.dic['province'] == '全国':
			self.cal_quanguo()
		elif self.keywords != 'null' and self.dic['sudu'] == '速度优先':
			self.buildxingzhengqu()
			if self.dic['xian'] == 'all':
				lxian = getadcode(self.dic['shi'], self.outputtext, self.lkey[0])
				for x in lxian:
					s = '%s 开始搜索区域 %s\n' % (gettime(), x)
					wx.CallAfter(self.outputtext.printmsg, s)
					self.adcode = x
					self.cal_keywords()
			else:
				self.cal_keywords()
		else:
			self.buildxingzhengqu()
			self.cal_loc()
		s = '%s 搜索完成\n' % gettime()
		wx.CallAfter(self.outputtext.printmsg, s)
		
	def cal_quanguo(self):
		#搜索全国poi
		lprovince = getadcode(100000, self.outputtext, self.lkey[0])
		bar = Bar(3297, self.outputtext)
		for adcode_sheng in lprovince:
			lshi = getadcode(adcode_sheng, self.outputtext, self.lkey[0])
			for adcode_shi in lshi:
				lxian = getadcode(adcode_shi, self.outputtext, self.lkey[0])
				for adcode_xian in lxian:
					urlone = 'http://restapi.amap.com/v3/place/text?key=%s&extensions=all&keywords=%s&city=%s' % (self.getkey(), self.keywords, adcode_xian)
					lurlmany = self.getpageall2(urlone)
					if len(lurlmany) > 0:
						self.requestmany(lurlmany)
					bar.cal()
	
	def cal_keywords(self):
		#用关键词查询
		#用矩形计算, 用户输入了行政区，也输入点对
		if self.adcode == '500100':
			self.adcode = '500000'
		elif self.adcode == '110100':
			self.adcode = '110000'
		elif self.adcode == '310100':
			self.adcode = '310000'
		elif self.adcode == '120100':
			self.adcode = '120000'
		self.urlbase = 'http://restapi.amap.com/v3/place/text'
		lurl_nopage = ['extensions=all']
		if self.keywords != 'null':
			lurl_nopage = [x + '&keywords={}'.format(self.keywords) for x in lurl_nopage]
		if self.adcode != 'null':
			lurl_nopage = [x + '&city={}'.format(self.adcode) for x in lurl_nopage]
		lurl_nopageall = []
		if self.lloc_out != 'null':
			for x in self.lloc_out:
				p1, p2 = x
				l = [x + '&polygon=%s,%s|%s,%s' % (p1[0], p1[1], p2[0], p2[1]) for x in lurl_nopage]
				lurl_nopageall = lurl_nopageall + l
		else:
			lurl_nopageall = lurl_nopage
		lurlmany = []
		bar = Bar(len(lurl_nopageall), self.outputtext)
		for url in lurl_nopageall:
			urlone = self.urlbase + '?'+ url + '&page=1&key={}'.format(self.getkey())
			#print(urlone)
			lurl = self.getpageall(urlone)
			lurlmany = lurlmany + lurl
			if len(lurlmany) >= 5:
				sout = self.requestmany(lurlmany)
				lurlmany = []
			bar.cal()
		if len(lurlmany) != 0:
			sout = self.requestmany(lurlmany)
			
	def return_in_or_not(self, p1, p2):
		#判断输入的点是否在行政区中，如果行政区为null返回是
		if self.polygon == 'null':
			return True
		elif point_in_polygon(p1, self.polygon) or point_in_polygon(p2, self.polygon):
			return True
		else:
			return False
		
	def cal_loc(self):
		#用矩形计算, 用户只输入了行政区，未输入点对
		lurlmany = []
		bar = Bar(len(self.lloc), self.outputtext)
		random.shuffle(self.lloc)
		for i in range(len(self.lloc)):
			p1, p2 = self.lloc[i]
			#判断输入的点在行政区范围里
			lurl_nopage = ['citylimit=True&extensions=all&types={}'.format(x) for x in self.lcate]
			lurl_nopage = [x + '&polygon=%s,%s|%s,%s' % (p1[0], p1[1], p2[0], p2[1]) for x in lurl_nopage]
			#print(lurl_nopage)
			if self.keywords != 'null':
				lurl_nopage = [x + '&keywords={}'.format(self.keywords) for x in lurl_nopage]
			if self.adcode != 'null':
				lurl_nopage = [x + '&city={}'.format(self.adcode) for x in lurl_nopage]
			for url in lurl_nopage:
				urlone = self.urlbase + '?'+ url + '&page=1&key={}'.format(self.getkey())
				lurl = self.getpageall(urlone)
				lurlmany = lurlmany + lurl
				if len(lurlmany) >= 5:
					sout = self.requestmany(lurlmany)
					lurlmany = []
			bar.cal()
		if len(lurlmany) != 0:
			sout = self.requestmany(lurlmany)
		
		
class Bar(object):
	#每隔1%显示一次进度条
	def __init__(self,all,outputtext,breaking = 1):
		self.all = all
		self.outputtext = outputtext
		self.now = 0
		self.one = float(all) * 0.01 * breaking
		self.part = self.one
		self.time1 = self.timenow()
		self.timesum = 0
		
	def timenow(self):
		s = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
		mytime = datetime.datetime.strptime(s,'%Y-%m-%d %H:%M:%S')
		return mytime
		
	def cal(self):
		self.now += 1
		if self.now >= self.part:
			time2 = self.timenow()
			self.timesum = (time2 - self.time1).seconds / 60.0
			timeall = float(self.timesum * self.all) / float(self.now)
			timeleft = timeall - self.timesum
			printpercent = int(float(self.now) / float(self.all) * 100)
			if timeleft < 1:
				timeleft = timeleft * 60
				printtime = int(timeleft)
				s = '%s 已完成%s%% 剩余%s秒\n' % (gettime(),printpercent,printtime)
				wx.CallAfter(self.outputtext.printmsg, s)
			elif timeleft <= 60:
				printtime = round(timeleft,2)
				s = '%s 已完成%s%% 剩余%s分钟\n' % (gettime(),printpercent,printtime)
				wx.CallAfter(self.outputtext.printmsg, s)
			else:
				timeleft = timeleft / 60.0
				printtime = round(timeleft,2)
				s = '%s 已完成%s%% 剩余:%s小时\n' % (gettime(),printpercent,printtime)
				wx.CallAfter(self.outputtext.printmsg, s)
			self.part = self.part + self.one	
		
		
if __name__ == '__main__':
	dic = {
	'lloc':["121.46", "31.30", "121.49", "31.20"],
	#'lloc':'null',
	'cate':['050000','040000', '030000'],
	'provincecode':310000,
	#'shicode':'null',
	'shicode':310100,
	'xiancode':'null',
	#'xiancode':310110,
	'type':'txt',
	'path': r"C:\Users\zqy\Desktop\temp\cxz.txt",
	#'keywords':'星巴克'
	'keywords':'null',
	'passwordnum':100,
	'key':'88a0d226e441f2d6995b51e4781308fa'
	}
	class a(object):
		def __init__(self):
			pass
		def AppendText(self,s):
			print(s)
	Gaode(dic, a())
	
	